#ifndef _IM_SERVER_CONNECTION_MANAGER_ADAPTER_
#define _IM_SERVER_CONNECTION_MANAGER_ADAPTER_

#include "ConnectionManagerService.h"

#include "im/common/common.h"
#include "melon/client/thrift_client_pool.h"
#include "melon/client/zk_service_locator.h"
#include "base/singleton.h"

namespace imserver {

#define CONNECTION_MANAGER_SERVER_KEY "/im/connection_manager_service/v1/shard_0"

using melon::client::ClientPool;

class ConnectionManagerAdapter : public base::Singleton<ConnectionManagerAdapter> {
public:

  int GetCometServiceKeyByUids(std::map<int64_t, std::string>& _return, const std::set<int64_t>& uids, int max_retry = 1) {
    for(int i = 0; i < max_retry; ++i) {
      ConnectionManagerServiceClient * client = pool_.Alloc(CONNECTION_MANAGER_SERVER_KEY);
      if (client == NULL) {
        LOG_ERROR("ConnectionManagerAdapter::GetCometServiceKeyByUids --> connect err.");
        return -1;
      }

      bool success = true;
      try {
        client->GetCometServiceKeyByUids(_return, uids);
        LOG_INFO("ConnectionManagerAdapter::GetCometServiceKeyByUids --> successfully." << " res_size:" << _return.size() <<
            " retry:" << i);
      } catch (const std::exception & e) {
        LOG_ERROR("ConnectionManagerAdapter::GetCometServiceKeyByUids --> err. error:" << e.what() << " retry:" << i);
        success = false;
      }
      pool_.Release(CONNECTION_MANAGER_SERVER_KEY, client, success);
      if (success) {
        return 0;
      }
    }
    return -2;
  }

  int AllocateCometServiceForUid(std::string& _return, int64_t uid, int max_retry = 1) {
    for(int i = 0; i < max_retry; ++i) {
      ConnectionManagerServiceClient * client = pool_.Alloc(CONNECTION_MANAGER_SERVER_KEY);
      if (client == NULL) {
        LOG_ERROR("ConnectionManagerAdapter::AllocateCometServiceForUid --> connect err. uid:" << uid);
        return -1;
      }

      bool success = true;
      try {
        client->AllocateCometServiceForUid(_return, uid);
        LOG_INFO("ConnectionManagerAdapter::AllocateCometServiceForUid --> successfully. uid:" << uid << " res:" <<
            _return << " retry:" << i);
      } catch (const std::exception & e) {
        LOG_ERROR("ConnectionManagerAdapter::AllocateCometServiceForUid --> err. error:" << e.what() << " uid:" <<
            uid << " retry:" << i);
        success = false;
      }
      pool_.Release(CONNECTION_MANAGER_SERVER_KEY, client, success);
      if (success) {
        return 0;
      }
    }
    return -2;
  }

  int RemoveCometServiceKeyByUids(const std::set<int64_t>& uids, int max_retry = 1) {
    for(int i = 0; i < max_retry; ++i) {
      ConnectionManagerServiceClient * client = pool_.Alloc(CONNECTION_MANAGER_SERVER_KEY);
      if (client == NULL) {
        LOG_ERROR("ConnectionManagerAdapter::RemoveCometServiceKeyByUids --> connect err.");
        return -1;
      }

      bool success = true;
      try {
        client->RemoveCometServiceKeyByUids(uids);
        LOG_INFO("ConnectionManagerAdapter::RemoveCometServiceKeyByUids --> successfully." << " retry:" << i);
      } catch (const std::exception & e) {
        LOG_ERROR("ConnectionManagerAdapter::RemoveCometServiceKeyByUids --> err. error:" << e.what() << " retry:" << i);
        success = false;
      }
      pool_.Release(CONNECTION_MANAGER_SERVER_KEY, client, success);
      if (success) {
        return 0;
      }
    }
    return -2;
  }

  int SetValidCometServiceForUid(int64_t uid, const std::string& comet_server_key, int max_retry = 1) {
    for(int i = 0; i < max_retry; ++i) {
      ConnectionManagerServiceClient * client = pool_.Alloc(CONNECTION_MANAGER_SERVER_KEY);
      if (client == NULL) {
        LOG_ERROR("ConnectionManagerAdapter::SetValidCometServiceForUid --> connect err. uid:" << uid <<
            " comet_server_key:" << comet_server_key);
        return -1;
      }

      bool success = true;
      try {
        client->SetValidCometServiceForUid(uid, comet_server_key);
        LOG_INFO("ConnectionManagerAdapter::SetValidCometServiceForUid --> successfully. uid:" << uid <<
            " comet_server_key:" << comet_server_key << " retry:" << i);
      } catch (const std::exception & e) {
        LOG_ERROR("ConnectionManagerAdapter::SetValidCometServiceForUid --> err. error:" << e.what() << " uid:" <<
            uid << " comet_server_key:" << comet_server_key << " retry:" << i);
        success = false;
      }
      pool_.Release(CONNECTION_MANAGER_SERVER_KEY, client, success);
      if (success) {
        return 0;
      }
    }
    return -2;
  }

  int GetSockServiceKeyByUids(std::map<int64_t, std::string>& _return, const std::set<int64_t>& uids, int max_retry = 1) {
    std::map<int64_t, std::string> res;
    for(int i = 0; i < max_retry; ++i) {
      ConnectionManagerServiceClient * client = pool_.Alloc(CONNECTION_MANAGER_SERVER_KEY);
      if (client == NULL) {
        LOG_ERROR("ConnectionManagerAdapter::GetSockServiceKeyByUids --> connect err.");
        return -1;
      }

      bool success = true;
      try {
        client->GetSockServiceKeyByUids(_return, uids);
        LOG_INFO("ConnectionManagerAdapter::GetSockServiceKeyByUids --> successfully." << " res_size:" << _return.size() <<
            " retry:" << i);
      } catch (const std::exception & e) {
        LOG_ERROR("ConnectionManagerAdapter::GetSockServiceKeyByUids --> err. error:" << e.what() << " retry:" << i);
        success = false;
      }
      pool_.Release(CONNECTION_MANAGER_SERVER_KEY, client, success);
      if (success) {
        return 0;
      }
    }
    return -2;
  }

  int AllocateSockServiceForUid(std::string& _return, int64_t uid, int max_retry = 1) {
    for(int i = 0; i < max_retry; ++i) {
      ConnectionManagerServiceClient * client = pool_.Alloc(CONNECTION_MANAGER_SERVER_KEY);
      if (client == NULL) {
        LOG_ERROR("ConnectionManagerAdapter::AllocateSockServiceForUid --> connect err. uid:" << uid);
        return -1;
      }

      bool success = true;
      try {
        client->AllocateSockServiceForUid(_return, uid);
        LOG_INFO("ConnectionManagerAdapter::AllocateSockServiceForUid --> successfully. uid:" << uid << " res:" <<
            _return << " retry:" << i);
      } catch (const std::exception & e) {
        LOG_ERROR("ConnectionManagerAdapter::AllocateSockServiceForUid --> err. error:" << e.what() << " uid:" <<
            uid << " retry:" << i);
        success = false;
      }
      pool_.Release(CONNECTION_MANAGER_SERVER_KEY, client, success);
      if (success) {
        return 0;
      }
    }
    return -2;
  }

  int RemoveSockServiceKeyByUids(const std::set<int64_t>& uids, int max_retry = 1) {
    for(int i = 0; i < max_retry; ++i) {
      ConnectionManagerServiceClient * client = pool_.Alloc(CONNECTION_MANAGER_SERVER_KEY);
      if (client == NULL) {
        LOG_ERROR("ConnectionManagerAdapter::RemoveSockServiceKeyByUids --> connect err.");
        return -1;
      }

      bool success = true;
      try {
        client->RemoveSockServiceKeyByUids(uids);
        LOG_INFO("ConnectionManagerAdapter::RemoveSockServiceKeyByUids --> successfully." << " retry:" << i);
      } catch (const std::exception & e) {
        LOG_ERROR("ConnectionManagerAdapter::RemoveSockServiceKeyByUids --> err. error:" << e.what() << " retry:" << i);
        success = false;
      }
      pool_.Release(CONNECTION_MANAGER_SERVER_KEY, client, success);
      if (success) {
        return 0;
      }
    }
    return -2;
  }

  int SetValidSockServiceForUid(int64_t uid, const std::string& sock_server_key, int max_retry = 1) {
    for(int i = 0; i < max_retry; ++i) {
      ConnectionManagerServiceClient * client = pool_.Alloc(CONNECTION_MANAGER_SERVER_KEY);
      if (client == NULL) {
        LOG_ERROR("ConnectionManagerAdapter::SetValidSockServiceForUid --> connect err. uid:" << uid <<
            " server_key:" << sock_server_key);
        return -1;
      }

      bool success = true;
      try {
        client->SetValidSockServiceForUid(uid, sock_server_key);
        LOG_INFO("ConnectionManagerAdapter::SetValidSockServiceForUid --> successfully. uid:" << uid <<
            " sock_server_key:" << sock_server_key << " retry:" << i);
      } catch (const std::exception & e) {
        LOG_ERROR("ConnectionManagerAdapter::SetValidSockServiceForUid --> err. error:" << e.what() << " uid:" <<
            uid << " sock_server_key:" << sock_server_key << " retry:" << i);
        success = false;
      }
      pool_.Release(CONNECTION_MANAGER_SERVER_KEY, client, success);
      if (success) {
        return 0;
      }
    }
    return -2;
  }

private:
  friend class base::Singleton<ConnectionManagerAdapter>;

  ConnectionManagerAdapter() {
    ConfigReader cfg("../conf/rpc_adapters.conf");
    std::string default_location(cfg.Get("connection_manager_service", "service_list"));
    pool_.set_default_location(default_location);

    ConfigReader zk_cfg("../conf/zookeeper.conf");
    if (!zk_cfg) {
      LOG_WARN("Config file ../conf/zookeeper.conf read error!");
      return;
    }
    pool_.set_locator(new melon::client::ZkServiceLocator(zk_cfg.Get("zookeeper", "service_registry").c_str()));
  }


  ClientPool<ConnectionManagerServiceClient> pool_;
};

}

#endif // _IM_SERVER_CONNECTION_MANAGER_ADAPTER_
